import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext, colorchooser, font, simpledialog
import os
from datetime import datetime
import re
import shutil
import base64
import json
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Protocol.KDF import PBKDF2

class NotepadApp:
    def __init__(self, root):
        self.root = root
        self.root.title("智能记事本 - 增强版")
        self.root.geometry("1200x800")
        
        # 当前文件路径
        self.current_file = None
        # 文本是否已修改
        self.text_modified = False
        # 最近打开的文件列表
        self.recent_files = []
        # 自动保存标志
        self.auto_save_enabled = True
        # 自动保存间隔（毫秒）
        self.auto_save_interval = 30000  # 30秒
        
        # 剪贴板历史
        self.clipboard_history = []
        self.max_clipboard_history = 10
        
        # 撤销/重做历史
        self.undo_stack = []
        self.redo_stack = []
        self.max_undo_steps = 100
        self.is_undo_redo_operation = False
        
        # 查找相关变量
        self.find_str = tk.StringVar()
        self.replace_str = tk.StringVar()
        self.match_case = tk.BooleanVar()
        self.search_results = []
        self.current_search_index = -1
        
        # 笔记管理相关
        self.default_storage_path = os.path.expanduser("~/MyNotes")
        self.recycle_bin_path = os.path.expanduser("~/RecycleBin")
        self.backup_enabled = True
        self.encryption_enabled = False
        self.current_folder = self.default_storage_path
        self.selected_notes = []
        self.note_tags = {}  # 存储笔记标签
        self.folder_structure = {}  # 存储文件夹结构
        
        # 确保必要目录存在
        os.makedirs(self.default_storage_path, exist_ok=True)
        os.makedirs(self.recycle_bin_path, exist_ok=True)
        
        self.setup_ui()
        self.setup_menu()
        self.setup_toolbar()
        self.setup_bindings()
        
        # 启动自动保存
        self.auto_save()
        # 启动自动备份
        self.auto_backup()
        # 刷新文件夹树
        self.refresh_folder_tree()
    
    def setup_ui(self):
        # 主框架
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 左侧面板（文件夹导航）
        self.sidebar_frame = ttk.Frame(main_frame, width=250)
        self.sidebar_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 5))
        self.sidebar_frame.pack_propagate(False)
        
        # 文件夹树形视图标题
        ttk.Label(self.sidebar_frame, text="笔记分类", font=("Arial", 10, "bold")).pack(pady=5)
        
        # 文件夹树形视图
        self.folder_tree = ttk.Treeview(self.sidebar_frame)
        self.folder_tree.heading("#0", text="文件夹结构", anchor=tk.W)
        self.folder_tree.pack(fill=tk.BOTH, expand=True)
        
        # 文件夹操作按钮
        folder_btn_frame = ttk.Frame(self.sidebar_frame)
        folder_btn_frame.pack(fill=tk.X, pady=5)
        ttk.Button(folder_btn_frame, text="新建文件夹", command=self.create_folder).pack(side=tk.LEFT, padx=2)
        ttk.Button(folder_btn_frame, text="刷新", command=self.refresh_folder_tree).pack(side=tk.LEFT, padx=2)
        
        # 右键菜单
        self.folder_menu = tk.Menu(self.folder_tree, tearoff=0)
        self.folder_menu.add_command(label="新建文件夹", command=self.create_folder)
        self.folder_menu.add_command(label="重命名", command=self.rename_folder)
        self.folder_menu.add_command(label="删除", command=self.delete_folder)
        
        self.folder_tree.bind("<Button-3>", self.show_folder_menu)
        self.folder_tree.bind("<<TreeviewSelect>>", self.on_folder_select)
        
        # 中间内容区域
        content_frame = ttk.Frame(main_frame)
        content_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        # 笔记列表框架
        notes_list_frame = ttk.Frame(content_frame)
        notes_list_frame.pack(fill=tk.BOTH, expand=True)
        
        # 笔记列表标题和排序控件
        notes_header_frame = ttk.Frame(notes_list_frame)
        notes_header_frame.pack(fill=tk.X, pady=(0, 5))
        
        ttk.Label(notes_header_frame, text="笔记列表", font=("Arial", 10, "bold")).pack(side=tk.LEFT)
        
        # 排序方式选择
        sort_frame = ttk.Frame(notes_header_frame)
        sort_frame.pack(side=tk.RIGHT)
        ttk.Label(sort_frame, text="排序:").pack(side=tk.LEFT)
        self.sort_var = tk.StringVar(value="title")
        sort_combo = ttk.Combobox(sort_frame, textvariable=self.sort_var, 
                                 values=["title", "mtime", "ctime"], width=10)
        sort_combo.pack(side=tk.LEFT, padx=2)
        sort_combo.bind("<<ComboboxSelected>>", self.refresh_notes_list)
        
        # 笔记列表
        self.notes_listbox = tk.Listbox(notes_list_frame, selectmode=tk.EXTENDED)
        self.notes_listbox.pack(fill=tk.BOTH, expand=True)
        self.notes_listbox.bind("<Double-Button-1>", self.open_selected_note)
        self.notes_listbox.bind("<Button-3>", self.show_notes_context_menu)
        
        # 笔记操作按钮
        notes_btn_frame = ttk.Frame(notes_list_frame)
        notes_btn_frame.pack(fill=tk.X, pady=5)
        ttk.Button(notes_btn_frame, text="新建笔记", command=self.new_file).pack(side=tk.LEFT, padx=2)
        ttk.Button(notes_btn_frame, text="打开", command=self.open_selected_note).pack(side=tk.LEFT, padx=2)
        ttk.Button(notes_btn_frame, text="删除", command=self.delete_selected_notes).pack(side=tk.LEFT, padx=2)
        
        # 文本区域
        self.text_area = scrolledtext.ScrolledText(
            content_frame, 
            wrap=tk.WORD,
            font=("Consolas", 11),
            undo=True,
            maxundo=self.max_undo_steps
        )
        self.text_area.pack(fill=tk.BOTH, expand=True)
        
        # 状态栏
        self.status_bar = ttk.Label(self.root, text="就绪", relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
        
        # 查找替换框架 (初始隐藏)
        self.find_replace_frame = ttk.Frame(self.root)
        
        ttk.Label(self.find_replace_frame, text="查找:").grid(row=0, column=0, padx=5, pady=5)
        ttk.Entry(self.find_replace_frame, textvariable=self.find_str, width=20).grid(row=0, column=1, padx=5, pady=5)
        ttk.Button(self.find_replace_frame, text="查找", command=self.find_text).grid(row=0, column=2, padx=5, pady=5)
        
        ttk.Label(self.find_replace_frame, text="替换:").grid(row=1, column=0, padx=5, pady=5)
        ttk.Entry(self.find_replace_frame, textvariable=self.replace_str, width=20).grid(row=1, column=1, padx=5, pady=5)
        ttk.Button(self.find_replace_frame, text="替换", command=self.replace_text).grid(row=1, column=2, padx=5, pady=5)
        ttk.Button(self.find_replace_frame, text="全部替换", command=self.replace_all).grid(row=1, column=3, padx=5, pady=5)
        
        ttk.Checkbutton(self.find_replace_frame, text="匹配大小写", variable=self.match_case).grid(row=0, column=3, padx=5, pady=5)
        ttk.Button(self.find_replace_frame, text="关闭", command=self.hide_find_replace).grid(row=1, column=4, padx=5, pady=5)
        
        # 批量操作框架 (初始隐藏)
        self.batch_frame = ttk.Frame(self.root)
        
        ttk.Label(self.batch_frame, text="批量操作:").pack(side=tk.LEFT, padx=5)
        ttk.Button(self.batch_frame, text="移动到", command=self.batch_move_notes).pack(side=tk.LEFT, padx=2)
        ttk.Button(self.batch_frame, text="添加标签", command=self.batch_add_tag).pack(side=tk.LEFT, padx=2)
        ttk.Button(self.batch_frame, text="删除标签", command=self.batch_remove_tag).pack(side=tk.LEFT, padx=2)
        ttk.Button(self.batch_frame, text="彻底删除", command=self.batch_permanent_delete).pack(side=tk.LEFT, padx=2)
        ttk.Button(self.batch_frame, text="取消选择", command=self.cancel_selection).pack(side=tk.LEFT, padx=2)
        
        # 更新状态栏
        self.update_status_bar()
    
    def setup_menu(self):
        # 创建菜单栏
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)
        
        # 文件菜单
        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="文件", menu=file_menu)
        
        # 模板子菜单
        template_menu = tk.Menu(file_menu, tearoff=0)
        file_menu.add_cascade(label="新建模板笔记", menu=template_menu)
        template_menu.add_command(label="待办事项模板", command=lambda: self.new_from_template("todo"))
        template_menu.add_command(label="日记模板", command=lambda: self.new_from_template("diary"))
        template_menu.add_command(label="新建空白笔记", command=self.new_file, accelerator="Ctrl+N")

        file_menu.add_command(label="打开", command=self.open_file, accelerator="Ctrl+O")
        
        # 最近文件子菜单
        self.recent_menu = tk.Menu(file_menu, tearoff=0)
        file_menu.add_cascade(label="最近打开", menu=self.recent_menu)
        self.update_recent_menu()
        
        file_menu.add_separator()
        file_menu.add_command(label="保存", command=self.save_file, accelerator="Ctrl+S")
        file_menu.add_command(label="另存为", command=self.save_as_file, accelerator="Ctrl+Shift+S")
        file_menu.add_command(label="加密保存", command=self.save_encrypted_note)
        file_menu.add_separator()
        file_menu.add_command(label="关闭", command=self.close_file)
        file_menu.add_command(label="退出", command=self.quit_app)
        
        # 编辑菜单
        edit_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="编辑", menu=edit_menu)
        edit_menu.add_command(label="撤销", command=self.undo, accelerator="Ctrl+Z")
        edit_menu.add_command(label="重做", command=self.redo, accelerator="Ctrl+Y")
        edit_menu.add_separator()
        edit_menu.add_command(label="剪切", command=self.cut, accelerator="Ctrl+X")
        edit_menu.add_command(label="复制", command=self.copy, accelerator="Ctrl+C")
        edit_menu.add_command(label="粘贴", command=self.paste, accelerator="Ctrl+V")
        
        # 剪贴板历史子菜单
        self.clipboard_menu = tk.Menu(edit_menu, tearoff=0)
        edit_menu.add_cascade(label="剪贴板历史", menu=self.clipboard_menu)
        self.update_clipboard_menu()
        
        edit_menu.add_separator()
        edit_menu.add_command(label="全选", command=self.select_all, accelerator="Ctrl+A")
        edit_menu.add_command(label="查找", command=self.show_find_replace, accelerator="Ctrl+F")
        edit_menu.add_command(label="替换", command=self.show_find_replace, accelerator="Ctrl+H")
        
        # 格式菜单
        format_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="格式", menu=format_menu)
        
        # 字体子菜单
        font_menu = tk.Menu(format_menu, tearoff=0)
        format_menu.add_cascade(label="字体", menu=font_menu)
        
        # 获取系统字体
        available_fonts = list(font.families())
        popular_fonts = ["Arial", "Times New Roman", "Courier New", "Consolas", "Verdana", "Tahoma", "微软雅黑", "宋体"]
        
        for f in popular_fonts:
            if f in available_fonts:
                font_menu.add_command(label=f, command=lambda font_name=f: self.change_font(font_name))
        
        font_menu.add_separator()
        font_menu.add_command(label="选择字体...", command=self.choose_font)
        
        # 字号子菜单
        size_menu = tk.Menu(format_menu, tearoff=0)
        format_menu.add_cascade(label="字号", menu=size_menu)
        
        for size in [8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28]:
            size_menu.add_command(label=str(size), command=lambda s=size: self.change_font_size(s))
        
        format_menu.add_separator()
        format_menu.add_command(label="粗体", command=self.toggle_bold, accelerator="Ctrl+B")
        format_menu.add_command(label="斜体", command=self.toggle_italic, accelerator="Ctrl+I")
        format_menu.add_command(label="下划线", command=self.toggle_underline, accelerator="Ctrl+U")
        format_menu.add_command(label="删除线", command=self.toggle_strikethrough)
        format_menu.add_separator()
        format_menu.add_command(label="文字颜色", command=self.change_text_color)
        format_menu.add_command(label="背景颜色", command=self.change_bg_color)
        format_menu.add_separator()
        format_menu.add_command(label="自动换行", command=self.toggle_word_wrap)
        
        # 存储菜单
        storage_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="存储", menu=storage_menu)
        storage_menu.add_command(label="设置默认存储路径", command=self.set_default_storage_path)
        storage_menu.add_command(label="启用自动备份", command=self.toggle_auto_backup)
        storage_menu.add_command(label="立即备份", command=self.manual_backup)
        storage_menu.add_command(label="查看回收站", command=self.show_recycle_bin)
        
        # 帮助菜单
        help_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="帮助", menu=help_menu)
        help_menu.add_command(label="关于", command=self.show_about)
    
    def setup_toolbar(self):
        # 创建工具栏
        toolbar = ttk.Frame(self.root)
        toolbar.pack(side=tk.TOP, fill=tk.X)
        
        # 撤销/重做按钮
        ttk.Button(toolbar, text="撤销", command=self.undo).pack(side=tk.LEFT, padx=2, pady=2)
        ttk.Button(toolbar, text="重做", command=self.redo).pack(side=tk.LEFT, padx=2, pady=2)
        
        # 分隔线
        ttk.Separator(toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, padx=5, pady=2, fill=tk.Y)
        
        # 剪贴板操作按钮
        ttk.Button(toolbar, text="剪切", command=self.cut).pack(side=tk.LEFT, padx=2, pady=2)
        ttk.Button(toolbar, text="复制", command=self.copy).pack(side=tk.LEFT, padx=2, pady=2)
        ttk.Button(toolbar, text="粘贴", command=self.paste).pack(side=tk.LEFT, padx=2, pady=2)
        
        # 分隔线
        ttk.Separator(toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, padx=5, pady=2, fill=tk.Y)
        
        # 格式按钮
        ttk.Button(toolbar, text="粗体", command=self.toggle_bold).pack(side=tk.LEFT, padx=2, pady=2)
        ttk.Button(toolbar, text="斜体", command=self.toggle_italic).pack(side=tk.LEFT, padx=2, pady=2)
        ttk.Button(toolbar, text="下划线", command=self.toggle_underline).pack(side=tk.LEFT, padx=2, pady=2)
        
        # 分隔线
        ttk.Separator(toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, padx=5, pady=2, fill=tk.Y)
        
        # 查找按钮
        ttk.Button(toolbar, text="查找", command=self.show_find_replace).pack(side=tk.LEFT, padx=2, pady=2)
        
        # 分隔线
        ttk.Separator(toolbar, orient=tk.VERTICAL).pack(side=tk.LEFT, padx=5, pady=2, fill=tk.Y)
        
        # 文件夹操作按钮
        ttk.Button(toolbar, text="新建文件夹", command=self.create_folder).pack(side=tk.LEFT, padx=2, pady=2)
        ttk.Button(toolbar, text="刷新", command=self.refresh_folder_tree).pack(side=tk.LEFT, padx=2, pady=2)
    
    def setup_bindings(self):
        self.text_area.bind("<KeyPress>", self.on_text_change)
        self.text_area.bind("<<Selection>>", self.on_selection_change)
        
        # 快捷键绑定
        self.root.bind("<Control-n>", lambda e: self.new_file())
        self.root.bind("<Control-o>", lambda e: self.open_file())
        self.root.bind("<Control-s>", lambda e: self.save_file())
        self.root.bind("<Control-Shift-S>", lambda e: self.save_as_file())
        self.root.bind("<Control-f>", lambda e: self.show_find_replace())
        self.root.bind("<Control-h>", lambda e: self.show_find_replace())
        self.root.bind("<Control-z>", lambda e: self.undo())
        self.root.bind("<Control-y>", lambda e: self.redo())
        self.root.bind("<Control-a>", lambda e: self.select_all())
        self.root.bind("<Control-b>", lambda e: self.toggle_bold())
        self.root.bind("<Control-i>", lambda e: self.toggle_italic())
        self.root.bind("<Control-u>", lambda e: self.toggle_underline())
        
        # 处理关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.quit_app)
        
        # 绑定Alt键进行列选择
        self.text_area.bind("<Alt-Button-1>", self.start_column_select)
        self.text_area.bind("<B1-Motion>", self.on_drag)
        self.text_area.bind("<ButtonRelease-1>", self.end_column_select)
        
        self.column_select_mode = False
        self.column_select_start = None
    
    def on_text_change(self, event=None):
        if not self.is_undo_redo_operation:
            self.text_modified = True
            self.update_status_bar()
    
    def on_selection_change(self, event=None):
        # 更新状态栏显示行列信息
        if hasattr(self, 'text_area'):
            try:
                cursor_index = self.text_area.index(tk.INSERT)
                line, column = map(int, cursor_index.split('.'))
                self.status_bar.config(text=f"行: {line}, 列: {column} | {self.status_bar.cget('text')}")
            except:
                pass
    
    def update_status_bar(self):
        status = "就绪"
        if self.current_file:
            status = f"当前文件: {os.path.basename(self.current_file)}"
        if self.text_modified:
            status += " | 已修改"
        self.status_bar.config(text=status)
    
    def update_recent_menu(self):
        self.recent_menu.delete(0, tk.END)
        if not self.recent_files:
            self.recent_menu.add_command(label="无最近文件", state=tk.DISABLED)
            return
        
        for file_path in self.recent_files:
            self.recent_menu.add_command(
                label=os.path.basename(file_path),
                command=lambda path=file_path: self.open_recent_file(path)
            )
    
    def update_clipboard_menu(self):
        self.clipboard_menu.delete(0, tk.END)
        if not self.clipboard_history:
            self.clipboard_menu.add_command(label="剪贴板为空", state=tk.DISABLED)
            return
        
        for i, content in enumerate(self.clipboard_history):
            # 显示前50个字符
            display_text = content[:50] + "..." if len(content) > 50 else content
            self.clipboard_menu.add_command(
                label=f"{i+1}. {display_text}",
                command=lambda c=content: self.paste_from_history(c)
            )
    
    def add_to_recent_files(self, file_path):
        if file_path in self.recent_files:
            self.recent_files.remove(file_path)
        self.recent_files.insert(0, file_path)
        # 只保留最近10个文件
        self.recent_files = self.recent_files[:10]
        self.update_recent_menu()
    
    def add_to_clipboard_history(self, content):
        if content.strip() and content not in self.clipboard_history:
            self.clipboard_history.insert(0, content)
            # 只保留最近几次记录
            self.clipboard_history = self.clipboard_history[:self.max_clipboard_history]
            self.update_clipboard_menu()
    
    def new_file(self):
        if self.check_save():
            self.text_area.delete(1.0, tk.END)
            self.current_file = None
            self.text_modified = False
            self.update_status_bar()
            self.root.title("智能记事本 - 新文件")
    
    def new_from_template(self, template_type):
        if self.check_save():
            self.text_area.delete(1.0, tk.END)
            
            if template_type == "todo":
                template_text = """# 待办事项列表
                
## 今日重要事项
- [ ] 示例任务1
- [ ] 示例任务2

## 本周计划
- [ ] 长期任务1
- [ ] 长期任务2

## 已完成事项
- [x] 已完成任务示例
"""
            elif template_type == "diary":
                today = datetime.now().strftime("%Y年%m月%d日")
                template_text = f"""# 日记 - {today}

## 今日心情


## 今日总结


## 明日计划


## 感恩事项
1. 
2. 
3. 
"""
            else:
                template_text = ""
            
            self.text_area.insert(1.0, template_text)
            self.current_file = None
            self.text_modified = True
            self.update_status_bar()
            self.root.title("智能记事本 - 新文件(模板)")
    
    def open_file(self, file_path=None):
        if self.check_save():
            if not file_path:
                file_path = filedialog.askopenfilename(
                    title="打开文件",
                    filetypes=[
                        ("文本文件", "*.txt"),
                        ("Markdown文件", "*.md"),
                        ("HTML文件", "*.html;*.htm"),
                        ("加密文件", "*.enc"),
                        ("所有文件", "*.*")
                    ]
                )
            
            if file_path:
                try:
                    if file_path.endswith('.enc'):
                        # 解密文件
                        password = tk.simpledialog.askstring("解密", "请输入密码:", show='*')
                        if not password:
                            return
                        with open(file_path, 'r') as file:
                            encrypted_content = file.read()
                        content = self.decrypt_note(encrypted_content, password)
                    else:
                        with open(file_path, 'r', encoding='utf-8') as file:
                            content = file.read()
                    
                    self.text_area.delete(1.0, tk.END)
                    self.text_area.insert(1.0, content)
                    self.current_file = file_path
                    self.text_modified = False
                    self.add_to_recent_files(file_path)
                    self.update_status_bar()
                    self.root.title(f"智能记事本 - {os.path.basename(file_path)}")
                except Exception as e:
                    messagebox.showerror("错误", f"无法打开文件: {str(e)}")
    
    def open_recent_file(self, file_path):
        if os.path.exists(file_path):
            self.open_file(file_path)
        else:
            messagebox.showerror("错误", f"文件不存在: {file_path}")
            self.recent_files.remove(file_path)
            self.update_recent_menu()
    
    def save_file(self):
        if self.current_file:
            try:
                content = self.text_area.get(1.0, tk.END)
                with open(self.current_file, 'w', encoding='utf-8') as file:
                    file.write(content)
                self.text_modified = False
                self.update_status_bar()
                return True
            except Exception as e:
                messagebox.showerror("错误", f"保存文件时出错: {str(e)}")
                return False
        else:
            return self.save_as_file()
    
    def save_as_file(self):
        file_path = filedialog.asksaveasfilename(
            title="另存为",
            defaultextension=".txt",
            filetypes=[
                ("文本文件", "*.txt"),
                ("Markdown文件", "*.md"),
                ("HTML文件", "*.html"),
                ("所有文件", "*.*")
            ]
        )
        
        if file_path:
            try:
                content = self.text_area.get(1.0, tk.END)
                with open(file_path, 'w', encoding='utf-8') as file:
                    file.write(content)
                
                self.current_file = file_path
                self.text_modified = False
                self.add_to_recent_files(file_path)
                self.update_status_bar()
                self.root.title(f"智能记事本 - {os.path.basename(file_path)}")
                return True
            except Exception as e:
                messagebox.showerror("错误", f"保存文件时出错: {str(e)}")
                return False
        return False
    
    def save_encrypted_note(self):
        if not self.current_file:
            file_path = filedialog.asksaveasfilename(
                title="加密保存",
                defaultextension=".enc",
                filetypes=[("加密文件", "*.enc")]
            )
            if not file_path:
                return
            self.current_file = file_path
        
        password = tk.simpledialog.askstring("加密保存", "请输入加密密码:", show='*')
        if not password:
            return
            
        content = self.text_area.get(1.0, tk.END)
        try:
            encrypted_content = self.encrypt_note(content, password)
            with open(self.current_file, 'w') as f:
                f.write(encrypted_content)
            self.text_modified = False
            self.update_status_bar()
            messagebox.showinfo("成功", "笔记已加密保存。")
        except Exception as e:
            messagebox.showerror("错误", f"加密保存失败: {str(e)}")
    
    def auto_save(self):
        if self.auto_save_enabled and self.text_modified:
            if self.current_file:
                self.save_file()
            # 如果是新文件且内容不为空，询问是否保存
            elif self.text_area.get(1.0, tk.END).strip():
                # 可以在这里实现自动保存到临时文件的功能
                pass
        
        # 再次调度自动保存
        self.root.after(self.auto_save_interval, self.auto_save)
    
    def close_file(self):
        if self.check_save():
            self.text_area.delete(1.0, tk.END)
            self.current_file = None
            self.text_modified = False
            self.update_status_bar()
            self.root.title("智能记事本")
    
    def quit_app(self):
        if self.check_save():
            self.root.destroy()
    
    def check_save(self):
        if self.text_modified:
            response = messagebox.askyesnocancel(
                "保存更改",
                "当前文档已修改，是否保存更改？"
            )
            
            if response is None:  # 取消
                return False
            elif response:  # 是
                return self.save_file()
            else:  # 否
                return True
        return True
    
    # 编辑功能实现
    def undo(self):
        try:
            self.is_undo_redo_operation = True
            self.text_area.edit_undo()
            self.text_modified = True
            self.update_status_bar()
        except tk.TclError:
            pass
        finally:
            self.is_undo_redo_operation = False
    
    def redo(self):
        try:
            self.is_undo_redo_operation = True
            self.text_area.edit_redo()
            self.text_modified = True
            self.update_status_bar()
        except tk.TclError:
            pass
        finally:
            self.is_undo_redo_operation = False
    
    def cut(self):
        if self.text_area.tag_ranges(tk.SEL):
            content = self.text_area.get(tk.SEL_FIRST, tk.SEL_LAST)
            self.add_to_clipboard_history(content)
            self.text_area.event_generate("<<Cut>>")
            self.text_modified = True
            self.update_status_bar()
    
    def copy(self):
        if self.text_area.tag_ranges(tk.SEL):
            content = self.text_area.get(tk.SEL_FIRST, tk.SEL_LAST)
            self.add_to_clipboard_history(content)
            self.text_area.event_generate("<<Copy>>")
    
    def paste(self):
        try:
            self.text_area.event_generate("<<Paste>>")
            self.text_modified = True
            self.update_status_bar()
        except tk.TclError:
            pass
    
    def paste_from_history(self, content):
        self.text_area.insert(tk.INSERT, content)
        self.text_modified = True
        self.update_status_bar()
    
    def select_all(self):
        self.text_area.tag_add(tk.SEL, "1.0", tk.END)
        self.text_area.mark_set(tk.INSERT, "1.0")
        self.text_area.see(tk.INSERT)
    
    # 查找替换功能
    def show_find_replace(self):
        self.find_replace_frame.pack(side=tk.BOTTOM, fill=tk.X)
        self.find_str.set("")
        self.replace_str.set("")
        self.find_str.focus()
    
    def hide_find_replace(self):
        self.find_replace_frame.pack_forget()
        self.text_area.tag_remove("search", "1.0", tk.END)
        self.text_area.tag_remove("current_search", "1.0", tk.END)
    
    def find_text(self):
        # 清除之前的搜索高亮
        self.text_area.tag_remove("search", "1.0", tk.END)
        self.text_area.tag_remove("current_search", "1.0", tk.END)
        
        search_str = self.find_str.get()
        if not search_str:
            return
        
        # 设置搜索标签样式
        self.text_area.tag_config("search", background="yellow")
        self.text_area.tag_config("current_search", background="orange")
        
        # 收集所有匹配项
        self.search_results = []
        start_pos = "1.0"
        
        while True:
            if self.match_case.get():
                pos = self.text_area.search(search_str, start_pos, stopindex=tk.END)
            else:
                pos = self.text_area.search(search_str, start_pos, stopindex=tk.END, nocase=1)
            
            if not pos:
                break
                
            end_pos = f"{pos}+{len(search_str)}c"
            self.search_results.append((pos, end_pos))
            self.text_area.tag_add("search", pos, end_pos)
            start_pos = end_pos
        
        if self.search_results:
            self.current_search_index = 0
            self.highlight_current_search()
        else:
            messagebox.showinfo("查找", "未找到匹配的文本")
    
    def highlight_current_search(self):
        if not self.search_results:
            return
            
        # 清除当前搜索高亮
        self.text_area.tag_remove("current_search", "1.0", tk.END)
        
        # 高亮当前搜索结果
        start, end = self.search_results[self.current_search_index]
        self.text_area.tag_add("current_search", start, end)
        self.text_area.see(start)
    
    def replace_text(self):
        if not self.text_area.tag_ranges(tk.SEL):
            self.find_text()
            return
            
        # 获取选中的文本
        sel_start = self.text_area.index(tk.SEL_FIRST)
        sel_end = self.text_area.index(tk.SEL_LAST)
        selected_text = self.text_area.get(sel_start, sel_end)
        
        # 检查选中的文本是否与查找文本匹配
        search_str = self.find_str.get()
        if (self.match_case.get() and selected_text == search_str) or \
           (not self.match_case.get() and selected_text.lower() == search_str.lower()):
            self.text_area.delete(sel_start, sel_end)
            self.text_area.insert(sel_start, self.replace_str.get())
            self.text_modified = True
            self.update_status_bar()
        
        # 查找下一个
        self.find_text()
    
    def replace_all(self):
        search_str = self.find_str.get()
        replace_str = self.replace_str.get()
        
        if not search_str:
            return
            
        # 获取所有文本
        content = self.text_area.get(1.0, tk.END)
        
        if self.match_case.get():
            new_content = content.replace(search_str, replace_str)
        else:
            pattern = re.compile(re.escape(search_str), re.IGNORECASE)
            new_content = pattern.sub(replace_str, content)
        
        # 替换文本
        self.text_area.delete(1.0, tk.END)
        self.text_area.insert(1.0, new_content)
        self.text_modified = True
        self.update_status_bar()
        
        messagebox.showinfo("替换", f"已完成 {content.count(search_str)} 处替换")
    
    # 格式功能
    def toggle_bold(self):
        current_font = font.Font(font=self.text_area.cget("font"))
        new_weight = "bold" if current_font.actual()["weight"] == "normal" else "normal"
        self.text_area.config(font=(current_font.actual()["family"], current_font.actual()["size"], new_weight))
    
    def toggle_italic(self):
        current_font = font.Font(font=self.text_area.cget("font"))
        new_slant = "italic" if current_font.actual()["slant"] == "roman" else "roman"
        self.text_area.config(font=(current_font.actual()["family"], current_font.actual()["size"], current_font.actual()["weight"], new_slant))
    
    def toggle_underline(self):
     try:
        # 获取当前字体配置
        current_font = font.Font(font=self.text_area.cget("font"))
        font_name = current_font.actual()["family"]
        font_size = current_font.actual()["size"]
        font_weight = current_font.actual()["weight"]
        font_slant = current_font.actual()["slant"]
        
        # 切换下划线状态
        new_underline = not current_font.actual()["underline"]
        
        # 创建新字体
        new_font = (font_name, font_size, font_weight, font_slant, "underline" if new_underline else "")
        
        # 如果有选中文本，只对选中文本应用样式
        if self.text_area.tag_ranges(tk.SEL):
            # 创建或更新下划线标签
            self.text_area.tag_configure("underline", font=new_font)
            self.text_area.tag_add("underline", tk.SEL_FIRST, tk.SEL_LAST)
        else:
            # 没有选中文本时，更改整个文本区域的字体
            self.text_area.config(font=new_font)
            
     except Exception as e:
        print(f"切换下划线时出错: {e}")
        # 备用方案：使用标签实现下划线效果
        self.toggle_underline_fallback()
    
    def toggle_strikethrough(self):
        # Tkinter 文本组件不支持删除线，这里使用标签实现
        if self.text_area.tag_ranges(tk.SEL):
            # 检查是否已有删除线标签
            if "strikethrough" in self.text_area.tag_names(tk.SEL_FIRST):
                self.text_area.tag_remove("strikethrough", tk.SEL_FIRST, tk.SEL_LAST)
            else:
                self.text_area.tag_add("strikethrough", tk.SEL_FIRST, tk.SEL_LAST)
    
    def change_font(self, font_name):
        current_font = font.Font(font=self.text_area.cget("font"))
        self.text_area.config(font=(font_name, current_font.actual()["size"]))
    
    def change_font_size(self, size):
        current_font = font.Font(font=self.text_area.cget("font"))
        self.text_area.config(font=(current_font.actual()["family"], size))
    
    def choose_font(self):
        # 字体选择对话框
        font_tuple = font.families()
        font_name = tk.simpledialog.askstring("选择字体", "请输入字体名称:", initialvalue=font.Font(font=self.text_area.cget("font")).actual()["family"])
        if font_name and font_name in font_tuple:
            self.change_font(font_name)
    
    def change_text_color(self):
        color = colorchooser.askcolor(title="选择文字颜色")
        if color[1]:
            self.text_area.config(fg=color[1])
    
    def change_bg_color(self):
        color = colorchooser.askcolor(title="选择背景颜色")
        if color[1]:
            self.text_area.config(bg=color[1])
    
    def toggle_word_wrap(self):
        current_wrap = self.text_area.cget("wrap")
        if current_wrap == tk.WORD:
            self.text_area.config(wrap=tk.NONE)
        else:
            self.text_area.config(wrap=tk.WORD)
    
    # 列选择模式
    def start_column_select(self, event):
        self.column_select_mode = True
        self.column_select_start = (event.x, event.y)
        self.text_area.mark_set("column_anchor", f"@{event.x},{event.y}")
    
    def on_drag(self, event):
        if self.column_select_mode and self.column_select_start:
            # 清除当前选择
            self.text_area.tag_remove(tk.SEL, "1.0", tk.END)
            
            # 获取起始和结束位置
            start_x, start_y = self.column_select_start
            end_x, end_y = event.x, event.y
            
            # 确保起始X小于结束X
            if start_x > end_x:
                start_x, end_x = end_x, start_x
            
            # 选择矩形区域
            self.text_area.tag_add(tk.SEL, f"@{start_x},{start_y}", f"@{end_x},{end_y}")
    
    def end_column_select(self, event):
        self.column_select_mode = False
        self.column_select_start = None
    
    # 文件夹管理功能
    def refresh_folder_tree(self):
        # 清空现有项目
        for item in self.folder_tree.get_children():
            self.folder_tree.delete(item)
        
        # 添加根目录
        root_node = self.folder_tree.insert("", "end", text=self.default_storage_path, values=[self.default_storage_path])
        self.add_folder_to_tree(root_node, self.default_storage_path)
        
        # 展开根节点
        self.folder_tree.item(root_node, open=True)
    
    def add_folder_to_tree(self, parent, path):
        try:
            for item in os.listdir(path):
                item_path = os.path.join(path, item)
                if os.path.isdir(item_path):
                    node = self.folder_tree.insert(parent, "end", text=item, values=[item_path])
                    self.add_folder_to_tree(node, item_path)
        except PermissionError:
            pass  # 忽略权限错误
    
    def show_folder_menu(self, event):
        try:
            self.folder_menu.tk_popup(event.x_root, event.y_root)
        finally:
            self.folder_menu.grab_release()
    
    def create_folder(self):
        selected = self.folder_tree.focus()
        if not selected:
            parent_path = self.default_storage_path
        else:
            parent_path = self.folder_tree.item(selected)['values'][0]
        
        folder_name = tk.simpledialog.askstring("新建文件夹", "请输入文件夹名:")
        if folder_name:
            full_path = os.path.join(parent_path, folder_name)
            try:
                os.makedirs(full_path, exist_ok=True)
                self.refresh_folder_tree()
                messagebox.showinfo("成功", f"文件夹 '{folder_name}' 创建成功。")
            except Exception as e:
                messagebox.showerror("错误", f"创建文件夹失败: {str(e)}")
    
    def rename_folder(self):
        selected = self.folder_tree.focus()
        if not selected:
            messagebox.showwarning("警告", "请先选择一个文件夹。")
            return
        
        old_path = self.folder_tree.item(selected)['values'][0]
        old_name = os.path.basename(old_path)
        new_name = tk.simpledialog.askstring("重命名", "请输入新名称:", initialvalue=old_name)
        if new_name and new_name != old_name:
            new_path = os.path.join(os.path.dirname(old_path), new_name)
            try:
                os.rename(old_path, new_path)
                self.refresh_folder_tree()
                messagebox.showinfo("成功", f"文件夹已重命名为 '{new_name}'。")
            except Exception as e:
                messagebox.showerror("错误", f"重命名失败: {str(e)}")
    
    def delete_folder(self):
        selected = self.folder_tree.focus()
        if not selected:
            messagebox.showwarning("警告", "请先选择一个文件夹。")
            return
        
        folder_path = self.folder_tree.item(selected)['values'][0]
        folder_name = os.path.basename(folder_path)
        
        if messagebox.askyesno("确认删除", f"确定要删除文件夹 '{folder_name}' 及其所有内容吗？"):
            try:
                # 移动到回收站而不是直接删除
                recycle_path = os.path.join(self.recycle_bin_path, f"{folder_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}")
                shutil.move(folder_path, recycle_path)
                self.refresh_folder_tree()
                messagebox.showinfo("成功", f"文件夹 '{folder_name}' 已移动到回收站。")
            except Exception as e:
                messagebox.showerror("错误", f"删除文件夹失败: {str(e)}")
    
    def on_folder_select(self, event):
        selected = self.folder_tree.focus()
        if selected:
            folder_path = self.folder_tree.item(selected)['values'][0]
            self.current_folder = folder_path
            self.refresh_notes_list()
    
    def refresh_notes_list(self, event=None):
        self.notes_listbox.delete(0, tk.END)
        if not os.path.exists(self.current_folder):
            return
            
        notes = self.sort_notes()
        for note in notes:
            self.notes_listbox.insert(tk.END, note)
    
    def sort_notes(self):
        if not os.path.exists(self.current_folder):
            return []
            
        notes = [f for f in os.listdir(self.current_folder) if f.endswith(('.txt', '.md', '.enc'))]
        sort_by = self.sort_var.get()
        
        if sort_by == "title":
            notes.sort()
        elif sort_by == "mtime":
            notes.sort(key=lambda x: os.path.getmtime(os.path.join(self.current_folder, x)), reverse=True)
        elif sort_by == "ctime":
            notes.sort(key=lambda x: os.path.getctime(os.path.join(self.current_folder, x)), reverse=True)
        
        return notes
    
    def open_selected_note(self, event=None):
        selection = self.notes_listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择一个笔记。")
            return
        
        note_name = self.notes_listbox.get(selection[0])
        note_path = os.path.join(self.current_folder, note_name)
        
        if note_path.endswith('.enc'):
            # 解密文件
            password = tk.simpledialog.askstring("解密", "请输入密码:", show='*')
            if not password:
                return
            try:
                with open(note_path, 'r') as file:
                    encrypted_content = file.read()
                content = self.decrypt_note(encrypted_content, password)
                self.text_area.delete(1.0, tk.END)
                self.text_area.insert(1.0, content)
                self.current_file = note_path
                self.text_modified = False
                self.update_status_bar()
                self.root.title(f"智能记事本 - {note_name}")
            except Exception as e:
                messagebox.showerror("错误", f"解密失败: {str(e)}")
        else:
            self.open_file(note_path)
    
    def delete_selected_notes(self):
        selection = self.notes_listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择要删除的笔记。")
            return
        
        if not messagebox.askyesno("确认删除", "确定要删除选中的笔记吗？"):
            return
        
        for index in reversed(selection):
            note_name = self.notes_listbox.get(index)
            note_path = os.path.join(self.current_folder, note_name)
            try:
                # 移动到回收站
                timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
                recycle_name = f"{note_name}_{timestamp}"
                recycle_path = os.path.join(self.recycle_bin_path, recycle_name)
                shutil.move(note_path, recycle_path)
            except Exception as e:
                messagebox.showerror("错误", f"删除笔记 '{note_name}' 失败: {str(e)}")
        
        self.refresh_notes_list()
        messagebox.showinfo("成功", "选中的笔记已移动到回收站。")
    
    # 批量操作功能
    def show_batch_operations(self):
        if self.notes_listbox.curselection():
            self.batch_frame.pack(side=tk.BOTTOM, fill=tk.X)
        else:
            self.batch_frame.pack_forget()
    
    def batch_move_notes(self):
        selection = self.notes_listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择要移动的笔记。")
            return
        
        # 选择目标文件夹
        target_folder = filedialog.askdirectory(title="选择目标文件夹")
        if not target_folder:
            return
        
        moved_count = 0
        for index in selection:
            note_name = self.notes_listbox.get(index)
            source_path = os.path.join(self.current_folder, note_name)
            target_path = os.path.join(target_folder, note_name)
            try:
                shutil.move(source_path, target_path)
                moved_count += 1
            except Exception as e:
                messagebox.showerror("错误", f"移动笔记 '{note_name}' 失败: {str(e)}")
        
        self.refresh_notes_list()
        messagebox.showinfo("成功", f"成功移动 {moved_count} 个笔记。")
    
    def batch_add_tag(self):
        selection = self.notes_listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择笔记。")
            return
        
        tag = tk.simpledialog.askstring("添加标签", "请输入标签名:")
        if not tag:
            return
        
        for index in selection:
            note_name = self.notes_listbox.get(index)
            if note_name not in self.note_tags:
                self.note_tags[note_name] = []
            if tag not in self.note_tags[note_name]:
                self.note_tags[note_name].append(tag)
        
        messagebox.showinfo("成功", f"标签 '{tag}' 已添加到选中的笔记。")
    
    def batch_remove_tag(self):
        selection = self.notes_listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择笔记。")
            return
        
        tag = tk.simpledialog.askstring("删除标签", "请输入要删除的标签名:")
        if not tag:
            return
        
        for index in selection:
            note_name = self.notes_listbox.get(index)
            if note_name in self.note_tags and tag in self.note_tags[note_name]:
                self.note_tags[note_name].remove(tag)
        
        messagebox.showinfo("成功", f"标签 '{tag}' 已从选中的笔记中删除。")
    
    def batch_permanent_delete(self):
        selection = self.notes_listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择要删除的笔记。")
            return
        
        if not messagebox.askyesno("确认永久删除", "确定要永久删除选中的笔记吗？此操作不可恢复！"):
            return
        
        deleted_count = 0
        for index in reversed(selection):
            note_name = self.notes_listbox.get(index)
            note_path = os.path.join(self.current_folder, note_name)
            try:
                if os.path.exists(note_path):
                    os.remove(note_path)
                    deleted_count += 1
            except Exception as e:
                messagebox.showerror("错误", f"删除笔记 '{note_name}' 失败: {str(e)}")
        
        self.refresh_notes_list()
        messagebox.showinfo("成功", f"成功永久删除 {deleted_count} 个笔记。")
    
    def cancel_selection(self):
        self.notes_listbox.selection_clear(0, tk.END)
        self.batch_frame.pack_forget()
    
    def show_notes_context_menu(self, event):
        # 显示批量操作菜单
        selection = self.notes_listbox.curselection()
        if selection:
            context_menu = tk.Menu(self.root, tearoff=0)
            context_menu.add_command(label="打开", command=self.open_selected_note)
            context_menu.add_command(label="删除", command=self.delete_selected_notes)
            context_menu.add_command(label="批量操作", command=self.show_batch_operations)
            context_menu.add_separator()
            context_menu.add_command(label="添加标签", command=self.batch_add_tag)
            context_menu.add_command(label="删除标签", command=self.batch_remove_tag)
            
            try:
                context_menu.tk_popup(event.x_root, event.y_root)
            finally:
                context_menu.grab_release()
    
    # 存储管理功能
    def set_default_storage_path(self):
        path = filedialog.askdirectory(title="选择默认笔记存储路径")
        if path:
            self.default_storage_path = path
            self.current_folder = path
            self.refresh_folder_tree()
            self.refresh_notes_list()
            messagebox.showinfo("成功", f"默认存储路径已设置为: {path}")
    
    def toggle_auto_backup(self):
        self.backup_enabled = not self.backup_enabled
        status = "启用" if self.backup_enabled else "禁用"
        messagebox.showinfo("备份设置", f"自动备份已{status}。")
    
    def manual_backup(self):
        try:
            backup_path = os.path.join(self.default_storage_path, "backup")
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            backup_folder = os.path.join(backup_path, timestamp)
            shutil.copytree(self.default_storage_path, backup_folder, 
                          ignore=shutil.ignore_patterns('backup'))
            messagebox.showinfo("备份成功", f"备份已创建到: {backup_folder}")
        except Exception as e:
            messagebox.showerror("备份失败", f"备份过程中出现错误: {str(e)}")
    
    def auto_backup(self):
        if self.backup_enabled:
            try:
                backup_path = os.path.join(self.default_storage_path, "backup")
                os.makedirs(backup_path, exist_ok=True)
                
                # 检查今天是否已备份
                today = datetime.now().strftime("%Y%m%d")
                today_backup = os.path.join(backup_path, today)
                
                if not os.path.exists(today_backup):
                    shutil.copytree(self.default_storage_path, today_backup,
                                  ignore=shutil.ignore_patterns('backup'))
            except Exception as e:
                print(f"自动备份失败: {e}")
        
        # 每天备份一次（24小时 = 86400000毫秒）
        self.root.after(86400000, self.auto_backup)
    
    def show_recycle_bin(self):
        if not os.path.exists(self.recycle_bin_path):
            messagebox.showinfo("回收站", "回收站为空。")
            return
        
        recycle_window = tk.Toplevel(self.root)
        recycle_window.title("回收站")
        recycle_window.geometry("600x400")
        
        # 回收站列表
        recycle_listbox = tk.Listbox(recycle_window)
        recycle_listbox.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 获取回收站中的文件
        recycled_items = os.listdir(self.recycle_bin_path)
        for item in recycled_items:
            recycle_listbox.insert(tk.END, item)
        
        # 操作按钮
        btn_frame = ttk.Frame(recycle_window)
        btn_frame.pack(fill=tk.X, padx=10, pady=5)
        
        def restore_selected():
            selection = recycle_listbox.curselection()
            if not selection:
                messagebox.showwarning("警告", "请先选择要恢复的项目。")
                return
            
            item_name = recycle_listbox.get(selection[0])
            source_path = os.path.join(self.recycle_bin_path, item_name)
            
            # 尝试恢复到原位置
            original_name = item_name.split('_')[0]  # 简单处理，实际应该保存原始路径
            target_path = os.path.join(self.default_storage_path, original_name)
            
            # 如果目标已存在，添加时间戳
            if os.path.exists(target_path):
                timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
                target_path = f"{target_path}_{timestamp}"
            
            try:
                shutil.move(source_path, target_path)
                recycle_listbox.delete(selection[0])
                messagebox.showinfo("成功", f"项目已恢复到: {target_path}")
            except Exception as e:
                messagebox.showerror("错误", f"恢复失败: {str(e)}")
        
        def delete_permanently():
            selection = recycle_listbox.curselection()
            if not selection:
                messagebox.showwarning("警告", "请先选择要永久删除的项目。")
                return
            
            if not messagebox.askyesno("确认删除", "确定要永久删除选中的项目吗？此操作不可恢复！"):
                return
            
            item_name = recycle_listbox.get(selection[0])
            item_path = os.path.join(self.recycle_bin_path, item_name)
            
            try:
                if os.path.isdir(item_path):
                    shutil.rmtree(item_path)
                else:
                    os.remove(item_path)
                recycle_listbox.delete(selection[0])
                messagebox.showinfo("成功", "项目已永久删除。")
            except Exception as e:
                messagebox.showerror("错误", f"删除失败: {str(e)}")
        
        ttk.Button(btn_frame, text="恢复", command=restore_selected).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="永久删除", command=delete_permanently).pack(side=tk.LEFT, padx=5)
        ttk.Button(btn_frame, text="关闭", command=recycle_window.destroy).pack(side=tk.RIGHT, padx=5)
    
    # 加密功能
    def encrypt_note(self, content, password):
        salt = get_random_bytes(16)
        key = PBKDF2(password, salt, dkLen=32)
        cipher = AES.new(key, AES.MODE_EAX)
        ciphertext, tag = cipher.encrypt_and_digest(content.encode())
        encrypted_data = base64.b64encode(salt + cipher.nonce + tag + ciphertext).decode()
        return encrypted_data

    def decrypt_note(self, encrypted_data, password):
        try:
            data = base64.b64decode(encrypted_data)
            salt = data[:16]
            nonce = data[16:32]
            tag = data[32:48]
            ciphertext = data[48:]
            key = PBKDF2(password, salt, dkLen=32)
            cipher = AES.new(key, AES.MODE_EAX, nonce=nonce)
            plaintext = cipher.decrypt_and_verify(ciphertext, tag)
            return plaintext.decode()
        except Exception as e:
            raise ValueError("解密失败，请检查密码是否正确。")
    
    def show_about(self):
        about_text = """智能记事本 - 增强版

功能特性:
- 笔记分类管理（文件夹层级）
- 笔记排序与批量操作
- 加密存储保护隐私
- 自动备份与回收站
- 丰富的编辑和格式功能

新增功能:
- 剪贴板历史
- 增强的查找替换
- 文本格式调整
- 列选择模式
- 模板支持"""
        messagebox.showinfo("关于", about_text)

if __name__ == "__main__":
    root = tk.Tk()
    app = NotepadApp(root)
    root.mainloop()